到目前為止,
雖然已經可以修改網頁的翻譯文字,
但只要重新載入網頁,
甚至只要切換原文、譯文,
辛苦修改的翻譯就會全部消失。
還記得嗎?我們從一開始就認定,
人 —— 才是更好的翻譯師。
人所修改過的翻譯,
才是超越機器翻譯、更好的譯文。
這些珍貴的譯文,
沒保存起來重複再利用,
實在太可惜了!!!
雖然我們可以用 Ctrl+S 的方式,
把修改過的頁面保存起來,
但如果想重新載入之前的翻譯、繼續進行修改,
這種保存方式並不好用。
我們希望可以把好不容易建立起來的好譯文保存起來,
之後來到同一個頁面,還可以重新載入譯文繼續改進。
HTML5 提供了一些新的資料保存方式,
其中有個叫做 localStorage 的功能,
我們就來看看怎麼運用吧。
首先,在完成分句、備份原始 sent 時,
我們就可以把各句的原文保存到 localStorage 中。
localStorage.setItem('orig_texts', JSON.stringify(orig_texts))
localStorage.setItem('orig_htmls', JSON.stringify(orig_htmls))
同樣的,在備份譯文時,
也可以把各句的譯文保存到 localStorage 中。
localStorage.setItem('tran_texts', JSON.stringify(tran_texts))
localStorage.setItem('tran_htmls', JSON.stringify(tran_htmls))
這裡要特別說明的是,
由於所要保存的資料都是 object 物件,
但 localStorage 只能保存 string 字串,
因此我們會先用 JSON.stringify(),
把資料轉成字串的形式再保存起來。
保存好原文、譯文的資料之後,
後續若要切換原文、譯文,
就可以從 localStorage 裡取出資料。
tran_texts = JSON.parse(localStorage.getItem('tran_texts'))
tran_htmls = JSON.parse(localStorage.getItem('tran_htmls'))
由於我們之前把資料保存為 string 字串的形式,
所以取出資料之後,還要利用 JSON.parse() 這個函式,
把資料還原成原本的 object 物件形式。
取回資料之後,就可以直接代入各句了。
document.querySelectorAll("sent").forEach((node, i)=>{
...
node.innerHTML = tran_htmls[i]
...
}
另外,我們也會在編輯界面中,修改這些譯句資料。
修改完成之後,
我們會在 confirmModification() 這個函式內確認修改,
因此我們也要在這個函式內,
利用修改過的內容更新 localStorage 裡的資料。
// 保存修改
i = parseInt(prev_sent_id.replace('sent_',''))
tran_texts[i] = prev_sent.textContent
tran_htmls[i] = prev_sent.innerHTML
// 保存到 localStorage
localStorage.setItem('tran_texts', JSON.stringify(tran_texts))
localStorage.setItem('tran_htmls', JSON.stringify(tran_htmls))
既然我們已經把修改過的譯文保存起來,
將來回到相同頁面時,
就不需要再用 Alt+123 取得每個句子的譯文,
直接按下【Alt+上】的快速鍵,
就能切換原文、譯文了。
...
else if (e.altKey && e.key=='ArrowUp') {
...
// 如果尚未分句,先進行分句
if (!document.body.innerHTML.match(/<\/sent>/)) {
document.body.innerHTML = addSentTag2HTML(document.body.innerHTML);
}
...
// 如果有之前的翻譯,就直接套入
if (tran_htmls && i in tran_htmls) {
node.innerHTML = tran_htmls[i]
}
}
你也可以直接到瀏覽器後台的「廚房」裡查看。
只要用【F12】打開後台,
再點選上方的 Application 頁簽,
然後點擊左欄 Storage 裡的 Local Storage,
就可以看到裡頭會以網域為名,建立一個項目。
只要點擊該項目,
就可以在右邊看到所保存的資料了。
在這裡也可以看到,
這些保存起來的資料,
全都是相同網域一起共用的資料。
換句話說,
如果進入相同網域的另一個頁面,
剛才保存的資料還是可以使用。
但問題是,
換到相同網域的另一個網頁之後,
除了一些導覽列之類的內容或許相同之外,
大部分的分句結果全都不一樣了。
因此,我們的資料應該隨著不同網址路徑,
分別進行記錄才行。
既然 localStorage 不會區分不同的網址路徑,
我們就要自行區分記錄。
做法上也很簡單,
只要在保存記錄時,採用網址路徑做為索引 key
再把資料掛進該索引下即可:
var path = window.location.pathname + window.location.search
...
// 保存到 localStorage
var tran_htmls_by_path = JSON.parse(localStorage.getItem('tran_htmls_by_path'))
if (!tran_htmls_by_path) {
tran_htmls_by_path = {}
}
tran_htmls_by_path[path] = tran_htmls
localStorage.setItem('tran_htmls_by_path', JSON.stringify(tran_htmls_by_path))
... 其餘以此類推 ...
用網址路徑做為索引,
有一些比較細緻的考量。
比方說,有些網頁的路徑末尾處,會用 # 引導至頁面某處,
這會造成同一個頁面對應多個不同網址字串的情況。
不過這裡採用的是 window.location.pathname,
並不會包含 # 的部分。
另外,網址末尾的參數字串,也會影響頁面的內容,
所以這裡利用了 window.location.search,
讓這段字串成為索引的一部分。
保存好資料之後,如果想要取資料,
倒過來做就可以了。
tran_htmls_by_path = JSON.parse(localStorage.getItem('tran_htmls_by_path'))
if (tran_htmls_by_path && path in tran_htmls_by_path) {
tran_htmls = tran_htmls_by_path[path]
}
... 其餘以此類推 ...
這樣一來,
用 localStorage 保存原文、譯文資料的做法,
就算是達到一定的完善程度了。
各位可以看到,
localSotrage 是一種蠻方便的做法,
它可以針對同一個網域,
保存一些可重複使用的資料。
如果好好運用這個特性,
甚至可以讓相同網域內重複出現的句子,
只需要翻譯過一次就可多處使用。
不過,localStorage 的做法,
終究還是有 5MB 的容量限制,
面對像是維基百科這種具有大量頁面的網域時,
恐怕就不夠用了。
另外,
就算只修改其中一個句子,
每次都要存取所有資料的做法,
也不是很有效率。
我們當然也可以針對每個句子,
各別保存相應的資料,
但若要查詢、修改、刪除資料,
相對來說還是頗為麻煩。
明天我們打算介紹 Web SQL,
這是另一種保存資料的做法。
它可以讓我們各別處理單一句子記錄,
而且只要使用者授權,
理論上來說並沒有容量上的限制。
今天就先聊到這裡,
明天我們再繼續囉。